using System;
using System.Linq;
using System.Web.Mvc;
using System.Collections.Generic;

using Orchard;
using Orchard.Localization;
using Orchard.ContentManagement;
using Orchard.Security;
using Orchard.UI.Notify;

using Orchard.Messaging.Services;
using Orchard.Mvc.Extensions;
using Orchard.Environment.Extensions;
using Orchard.Core.Title.Models;
using System.Text.RegularExpressions;
using FruitCake.ContactPage.Services;

namespace FruitCake.ContactPage.Controllers
{    
    [OrchardFeature("FruitCake.ContactPage")]
    public class FormController : Controller
    {
        private readonly IOrchardServices _services;        
        private readonly IMessageManager _messageManager;
        private readonly INotifier _notifier;
        private readonly IContactService _contactService;

        public FormController(
            IOrchardServices orchardServices,
            IMessageManager messageManager,
            INotifier notifier,
            IContactService contactService)
        {
            _services = orchardServices;
            _messageManager = messageManager;
            _notifier = notifier;
            _contactService = contactService;
        }

        public Localizer T { get; set; }

        [HttpPost, ValidateInput(false)]
        public ActionResult Send(int contentItemId, string returnUrl, string urlReferrer)
        {
            if (!_services.Authorizer.Authorize(Permissions.SendContactRequest, T("Not allowed to send request")))
                return new HttpUnauthorizedResult();

            // Parent redirect
            TempData["ContactPage.UrlReferrer"] = urlReferrer;

            if (!string.IsNullOrWhiteSpace(urlReferrer))
            {
                Uri urlRefUri = new Uri(urlReferrer);

                if (!Request.Url.Host.Equals(urlRefUri.Host))
                {
                    urlReferrer = "";
                }
            }

            // Content item
            var content = _services.ContentManager.Get(contentItemId);
            if (content == null || !content.Has<Models.ContactPagePart>())
            {
                _notifier.Error(T("Invalid submission"));
                return this.RedirectLocal(returnUrl, "~/");
            }

            string contentPage = content.As<TitlePart>().Title;

            // Input
            var model = new ViewModels.ContactPageFormViewModel();
            Models.ContactPagePart part = content.As<Models.ContactPagePart>();

            TryUpdateModel(model);

            if (!string.IsNullOrWhiteSpace(model.Mail))
            {
                Regex checkMail = new Regex(@"^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,6}$");
                if (!checkMail.IsMatch(model.Mail))
                    ModelState.AddModelError("Mail", T("Please check your email address."));
            }

            if (!part.IsNameVisible)
                ModelState["Name"].Errors.Clear();
            if (!part.IsReasonVisible)
                ModelState["ReasonIndex"].Errors.Clear();
            if (!part.IsSubjectVisible)
                ModelState["Subject"].Errors.Clear();

            if (!ModelState.IsValid)
            {
                foreach (var error in ModelState.Values.SelectMany(m => m.Errors).Select(e => e.ErrorMessage))
                {
                    _notifier.Error(T(error));
                }

                TempData["ContactPage.Name"] = model.Name;
                TempData["ContactPage.Mail"] = model.Mail;
                TempData["ContactPage.ReasonIndex"] = model.ReasonIndex;
                TempData["ContactPage.Subject"] = model.Subject;
                TempData["ContactPage.Text"] = model.Text;
            }
            else
            {
                Dictionary<String, String> props = PrepareProperties(part, model, content.As<TitlePart>().Title);

                int requestId = _contactService.SaveRequest(ViewModelToRequest(model, contentPage, props["Reason"]));
                props.Add("RequestId", requestId.ToString());
                props.Add("RequestCode", requestId.ToString("000000"));
                
                if (part.MailEnabled)
                {
                    if (!string.IsNullOrWhiteSpace(props["ToList"]))
                    {
                        string[] addresses = props["ToList"].Split(new char[] { ';', ',' }, StringSplitOptions.RemoveEmptyEntries);

                        string subject = ComposeSubject(part);
                        string body = ComposeBody(part);

                        props.Add("MailSubject", ReplaceInlineParams(subject, props));
                        props.Add("MailBody", ReplaceInlineParams(body, props));

                        _messageManager.Send(addresses, "ContactPage", "Email", props);
                    }
                }

                // Success
                LocalizedString sentMessage = string.IsNullOrWhiteSpace(part.SentMessage) ? T("Thank you for your message.") : T(part.SentMessage);
                _services.Notifier.Information(sentMessage);

                // Redirect
                if (!string.IsNullOrWhiteSpace(part.RedirectTo)) return this.RedirectLocal(part.RedirectTo, "~/");
                if (!string.IsNullOrWhiteSpace(urlReferrer)) return this.Redirect(urlReferrer);
            }

            return this.RedirectLocal(returnUrl, "~/");
        }

        public Models.ContactRequestRecord ViewModelToRequest(
            ViewModels.ContactPageFormViewModel model, 
            string contentPage,
            string reason)
        {
            return new Models.ContactRequestRecord()
                {
                    RequestDate = DateTime.Now,
                    ContactPage = contentPage,

                    Name = model.Name,
                    Mail = model.Mail,
                    Reason = reason,
                    Subject = model.Subject,
                    Text = model.Text,

                    StateValue = Models.RequestState.Pending,
                    StateUser = "",
                    StateDate = DateTime.Now
                };
        }

        private Dictionary<string, string> PrepareProperties(Models.ContactPagePart part, ViewModels.ContactPageFormViewModel model, string contentTitle)
        {
            string toList = "";
            string ccList = "";
            string bccList = "";
            string reason = "";

            if (part.IsReasonVisible)
            {
                int index = string.IsNullOrWhiteSpace(model.ReasonIndex) ? 0 : int.Parse(model.ReasonIndex);

                IEnumerable<Models.ReasonRule> rules = part.GetReasonRules();
                if (rules == null) rules = _contactService.GetDefaultReasons();

                Models.ReasonRule rule = rules.ElementAt(index);

                toList = string.IsNullOrWhiteSpace(rule.ToList) ? part.ToList : rule.ToList;
                ccList = string.IsNullOrWhiteSpace(rule.CcList) ? part.CcList : rule.CcList;
                bccList = string.IsNullOrWhiteSpace(rule.BccList) ? part.BccList : rule.BccList;

                reason = rule.Text;
            }
            else
            {
                toList = part.ToList;
                ccList = part.CcList;
                bccList = part.BccList;
            }

            //var recipient = _membershipService.GetUser(settings.RecipientUserName);
            //if (recipient == null || String.IsNullOrEmpty(recipient.Email))

            if (toList == "#") toList = "";
            if (ccList == "#") ccList = "";
            if (bccList == "#") bccList = "";

            // Properties
            Dictionary<string, string> props = new Dictionary<String, String>();

            props.Add("Title", contentTitle);
            props.Add("Host", Request.UserHostAddress);

            props.Add("Name", model.Name);
            props.Add("Mail", model.Mail);
            props.Add("Subject", model.Subject);
            props.Add("Reason", reason);
            props.Add("Text", model.Text);
           
            props.Add("SiteName", _services.WorkContext.CurrentSite.SiteName);
            props.Add("SiteUrl", _services.WorkContext.CurrentSite.BaseUrl);

            if (_services.WorkContext.CurrentUser != null)
            {
                IUser user = _services.WorkContext.CurrentUser;

                props.Add("UserId", user.Id.ToString());
                props.Add("UserName", user.UserName);
                props.Add("UserMail", user.Email);
            }
            else
            {
                props.Add("UserId", "");
                props.Add("UserName", "");
                props.Add("UserMail", "");
            }

            props.Add("RequestDateTime", DateTime.Now.ToLongDateString());
            props.Add("RequestDateTimeUTC", DateTime.Now.ToUniversalTime().ToString("G"));

            props.Add("ToList", toList);
            props.Add("CcList", ccList);
            props.Add("BccList", bccList);

            return props;
        }

        private string ComposeSubject(Models.ContactPagePart part)
        {
            if (!string.IsNullOrWhiteSpace(part.SubjectTemplate)) return part.SubjectTemplate;

            string template = T("{SiteName} [{RequestCode}]: ").ToString();
            
            if (part.IsReasonVisible) template += T("{Reason} - ");
            if (part.IsSubjectVisible) template += T("{Subject} - ");
            template += T("<{Mail}>");

            return template;
        }

        private string ComposeBody(Models.ContactPagePart part)
        {
            if (!string.IsNullOrWhiteSpace(part.BodyTemplate)) return part.BodyTemplate;

            string template = T("Site:\t{SiteName}\nTitle:\t{Title}").ToString();
            template += T("\nRequestId:\t{RequestId}");

            if (part.IsReasonVisible) template += T("\nReason:\t{Reason}");
            if (part.IsNameVisible) template += T("\nName:\t{Name}");

            template += T("\nMail:\t{Mail}");
            template += T("\nHost:\t{Host}").ToString();
            template += T("\nUserName:\t{UserName}").ToString();
            template += T("\nDateTimeUTC:\t{RequestDateTimeUTC}").ToString();

            template += T("\n\n{Text}").ToString();

            return template;
        }

        private string ReplaceInlineParams(string text, IDictionary<string, string> props)
        {
            foreach (KeyValuePair<string, string> pair in props)
                text = text.Replace("{" + pair.Key + "}", pair.Value);
            return text;
        }
    }
}
